package redlib.backend.service.impl;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import redlib.backend.dao.InstrumentMapper;
import redlib.backend.dto.InstrumentDTO;
import redlib.backend.dto.query.InstrumentQueryDTO;
import redlib.backend.model.*;
import redlib.backend.service.AdminService;
import redlib.backend.service.InstrumentService;
import redlib.backend.service.utils.InstrumentUtils;
import redlib.backend.utils.FormatUtils;
import redlib.backend.utils.PageUtils;
import redlib.backend.utils.ThreadContextHolder;
import redlib.backend.vo.InstrumentVO;
import redlib.backend.vo.InstrumentStatisticsVO;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 崔宇鑫
 * @description
 * @date 2023/3/17 12:33
 */
@Service
public class InstrumentServiceImpl implements InstrumentService {
    @Autowired
    private InstrumentMapper instrumentMapper;

    @Autowired
    private AdminService adminService;

    /**
     * 分页获取实验室仪器信息
     *
     * @param queryDTO 查询条件和分页信息
     * @return 带分页信息的仪器数据列表
     */
    @Override
    public Page<InstrumentVO> listByPage(InstrumentQueryDTO queryDTO) {
        if (queryDTO == null) {
            queryDTO = new InstrumentQueryDTO();
        }
        if (queryDTO.getInstrumentName() != null) {
            queryDTO.setInstrumentName(FormatUtils.makeFuzzySearchTerm(queryDTO.getInstrumentName()));
        }
        if (queryDTO.getRoomNumber() != null) {
            queryDTO.setRoomNumber(FormatUtils.makeFuzzySearchTerm(queryDTO.getRoomNumber()));
        }
        if (queryDTO.getBorrowedBy() != null) {
            queryDTO.setBorrowedBy(FormatUtils.makeFuzzySearchTerm(queryDTO.getBorrowedBy()));
        }

        if (queryDTO.getMaxPrice() != null) {
            queryDTO.setMaxPrice(queryDTO.getMaxPrice());
        }

        if (queryDTO.getMinPrice() != null) {
            queryDTO.setMinPrice(queryDTO.getMinPrice());
        }

        Integer size = instrumentMapper.count(queryDTO);
        PageUtils pageUtils = new PageUtils(queryDTO.getCurrent(), queryDTO.getPageSize(), size);

        if (size == 0) {
            // 没有命中，则返回空数据。
            return pageUtils.getNullPage();
        }

        // 利用myBatis到数据库中查询数据，以分页的方式
        List<Instrument> list = instrumentMapper.list(queryDTO, pageUtils.getOffset(), pageUtils.getLimit());

        // 提取list列表中的创建人字段，到一个Set集合中去
        Set<Integer> adminIds = list.stream().map(Instrument::getManager).collect(Collectors.toSet());

        // 提取list列表中的更新人字段，追加到集合中去
        adminIds.addAll(list.stream().map(Instrument::getManager).collect(Collectors.toSet()));

        // 获取id到人名的映射
        Map<Integer, String> nameMap = adminService.getNameMap(adminIds);

        List<InstrumentVO> voList = new ArrayList<>();
        for (Instrument instrument : list) {
            // Instrument对象转VO对象
            InstrumentVO vo = InstrumentUtils.convertToVO(instrument, nameMap);
            voList.add(vo);
        }
        return new Page<>(pageUtils.getCurrent(), pageUtils.getPageSize(), pageUtils.getTotal(), voList);
    }

    /**
     * 新建实验室仪器借用记录
     *
     * @param instrumentDTO 实验仪器输入对象
     * @return 实验仪器编码
     */
    @Override
    public Integer addInstrument(InstrumentDTO instrumentDTO) {
        Token token = ThreadContextHolder.getToken();
        // 校验输入数据正确性
        InstrumentUtils.validateInstrument(instrumentDTO);
        Assert.isNull(instrumentMapper.getByName(instrumentDTO.getInstrumentName()), "实验仪器名称已经存在");
        // 创建实体对象，用以保存到数据库
        Assert.hasText(instrumentDTO.getInstrumentName(), "仪器名称不能为空");
        Assert.isTrue(instrumentDTO.getTotalNumber() > instrumentDTO.getAvailableNumber(), "仪器总数量应大于损坏仪器数量");
        Assert.hasText(String.valueOf(instrumentDTO.getRoomNumber()), "房间号不能为空");
        Assert.isTrue(instrumentDTO.getPrice() > 0, "仪器价格应大于0");
        Instrument instrument = new Instrument();
        // 将输入的字段全部复制到实体对象中
        BeanUtils.copyProperties(instrumentDTO, instrument);


        instrument.setManager(token.getUserId());

        // 调用DAO方法保存到数据库表
        instrumentMapper.insert(instrument);
        return instrument.getId();
    }

    /**
     * 更新仪器数据
     *
     * @param instrumentDTO 实验仪器输入对象
     * @return 实验仪器编码
     */
    @Override

    public Integer updateInstrument(InstrumentDTO instrumentDTO) {
        // 校验输入数据正确性
        Token token = ThreadContextHolder.getToken();
        InstrumentUtils.validateInstrument(instrumentDTO);
        Assert.notNull(instrumentDTO.getId(), "实验仪器id不能为空");
        Instrument instrument = instrumentMapper.selectByPrimaryKey(instrumentDTO.getId());
        Assert.notNull(instrument, "没有找到实验仪器，Id为：" + instrumentDTO.getId());

        BeanUtils.copyProperties(instrumentDTO, instrument);
        instrument.setManager(token.getUserId());
        instrumentMapper.updateByPrimaryKey(instrument);
        return instrument.getId();
    }

    /**
     * 根据编码列表，批量删除实验仪器
     *
     * @param ids 实验仪器列表
     */
    @Override
    public void deleteByCodes(List<Integer> ids) {
        Assert.notEmpty(ids, "实验仪器id列表不能为空");
        instrumentMapper.deleteByCodes(ids);
    }

    /**
     * 实验仪器统计图
     *
     */
    @Override
    public Statistics<InstrumentStatisticsVO> statistics() {
        Statistics<InstrumentStatisticsVO> data = new Statistics<>(new ArrayList<>());
        List<InstrumentStatistics> list = instrumentMapper.Statistics();
        for (InstrumentStatistics instrumentStatistics : list) {
            InstrumentStatisticsVO instrumentStatisticsVO = new InstrumentStatisticsVO();
            BeanUtils.copyProperties(instrumentStatistics, instrumentStatisticsVO);
            data.getList().add(instrumentStatisticsVO);
        }
        return data;
    }



    /**
     * 实验仪器报修
     *
     */
    @Override
    public void repairByCodes(List<Integer> ids) {
        Assert.notEmpty(ids, "实验仪器id列表不能为空");
        instrumentMapper.repairByCodes(ids);
    }

    /**
     * 实验仪器检修完毕
     *
     */
    @Override
    public void repairedByCodes(List<Integer> ids) {
        Assert.notEmpty(ids, "实验仪器id列表不能为空");
        instrumentMapper.repairedByCodes(ids);
    }


}

